import utility from 'utility';
import uuid from 'node-uuid';
import Promise from 'promise';
import * as ResultMsg from '../constrants/ResultMsg';
import logger from '../common/logger';
import { UserModel } from '../models';

const baseFields = 'name loginname email weixin qq avatar role is_star create_at';
const detailFields = 'name loginname weixin qq avatar accessToken role email url profile_image_url location signature profile is_star';
const authFields = 'name loginname email retrieveKey, retrieveTime';

export function find(appId, conditions, options) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof conditions !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof options !== 'object') options = null;
  conditions.appId = appId;
  const query = UserModel.find(conditions).select(baseFields).setOptions(options);
  return query.exec();
}

export function findOne(appId, conditions, options) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof conditions !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof options !== 'object') options = null;
  conditions.appId = appId;
  const query = UserModel.findOne(conditions).select(baseFields).setOptions(options);
  return query.exec();
}

export function findFullOne(appId, conditions, options) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof conditions !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof options !== 'object') options = null;
  conditions.appId = appId;
  const query = UserModel.findOne(conditions).setOptions(options);
  return query.exec();
}

export function findByNames(appId, names) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof names !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (!Array.isArray(names)) throw new Error(ResultMsg.NOT_ARRAY);
  const query = UserModel.find({appId: appId, loginname: { $in: names } }).select(baseFields);
  return query.exec();
}

export function findOneById(appId, id) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof id !== 'string' && typeof id !== 'object') throw new Error(ResultMsg.NO_ID);
  const query = UserModel.findOne({appId: appId, _id: id }).select(baseFields);
  return query.exec();
}

export function findOneDetailById(appId, id) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof id !== 'string' && typeof id !== 'object') throw new Error(ResultMsg.NO_ID);
  const query = UserModel.findOne({appId: appId, _id: id }).select(detailFields);
  return query.exec();
}

export function findOneByName(appId, name) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof name !== 'string') throw new Error(ResultMsg.NOT_STRING);
  const query = UserModel.findOne({appId: appId, loginname: new RegExp(`^${name}$`, 'i') }).select(baseFields);
  return query.exec();
}

export function findByIds(appId, ids) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof ids !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (!Array.isArray(ids)) throw new Error(ResultMsg.NOT_ARRAY);
  const query = UserModel.find({appId: appId, _id: { $in: ids } }).select(baseFields);
  return query.exec();
}

export function increaseScore(appId, authorId, { topicCount, replyCount }) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof authorId !== 'string' && typeof authorId !== 'object') throw new Error(ResultMsg.NO_ID);
  topicCount = !topicCount ? 0 : topicCount;
  replyCount = !replyCount ? 0 : replyCount;

  const data = {};
  if (topicCount != 0) {
    data.score = 5;
    data.topic_count = 1;
  }

  if (replyCount != 0) {
    data.score = 5;
    data.reply_count = 1;
  }

  const query = UserModel.findByIdAndUpdate(authorId, { $inc: data });
  return query.exec();
}

export function create(appId, {loginname, passwordHash, email, avatar, active }) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof loginname !== 'string'
    || typeof passwordHash !== 'string'
    || typeof email !== 'string') {
    throw new Error(ResultMsg.NOT_STRING);
  }

  const user = new UserModel();
  user.appId = appId;
  user.name = loginname;
  user.loginname = loginname;
  user.pass = passwordHash;
  user.email = email;
  user.avatar = avatar || '';
  user.active = active || false;
  user.accessToken = uuid.v4();

  return user.save();
}

export function update(appId, id, data) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof id !== 'string' && typeof id !== 'object') throw new Error(ResultMsg.NO_ID);
  if (typeof data !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  const query = UserModel.findByIdAndUpdate(id, { $set: data });
  return query.exec();
}

export function makeGravatar(email) {
  return `http://www.gravatar.com/avatar/${utility.md5(email.toLowerCase())}?size=48`;
}

export function getGravatar(user) {
  return user.avatar || makeGravatar(user.email);
}
